package demo.dcs.util;

import demo.java.lang.management.vo.ClientConstants;
import demo.java.lang.management.vo.EventType;
import demo.java.lang.management.vo.XmlySpan;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * @author mandy.hu
 * 
 */
public class NginxLogParseUtil {

    private static Logger logger = LoggerFactory.getLogger(NginxLogParseUtil.class);
	
	//  /mobile/others/ca/track/{toUid}/{pageId}/{pageSize}
	//  /mobile/others/ca/album/12566/1/2
	public static boolean checkTrackDetail(String urlStr, XmlySpan xmlySpan){
        if(urlStr.contains("/mobile/others/ca/track")){
        	xmlySpan.setServiceId("/mobile/others/ca/track");
        	String[] elements = urlStr.split("/");
        	if (elements.length== 8) {
        		xmlySpan.addProp("toUid", elements[5]);
        		xmlySpan.addProp("pageId", elements[6]);
        		xmlySpan.addProp("pageSize", elements[7]);
			}
        	return true;
        }
        return false;
	}
	//  /mobile/others/ca/album/track/{albumId}/{isAsc}/{pageId}/{pageSize}
	//  /mobile/others/ca/album/{toUid}/{pageId}/{pageSize}
	public static boolean checkAlbumDetail(String urlStr,XmlySpan xmlySpan){
        if(urlStr.contains("/mobile/others/ca/album")){
        	if (urlStr.contains("album/track")) {
        		xmlySpan.setServiceId("/mobile/others/ca/album/track");
        		String[] elements = urlStr.split("/");
            	if (elements.length== 10) {
            		xmlySpan.addProp("albumId", elements[6]);
            		xmlySpan.addProp("isAsc", elements[7]);
            		xmlySpan.addProp("pageId", elements[8]);
            		xmlySpan.addProp("pageSize", elements[9]);
    			}
			}else {
				xmlySpan.setServiceId("/mobile/others/ca/album");
				String[] elements = urlStr.split("/");
	        	if (elements.length== 8) {
	        		xmlySpan.addProp("toUid", elements[5]);
	        		xmlySpan.addProp("pageId", elements[6]);
	        		xmlySpan.addProp("pageSize", elements[7]);
				}
			}
        	return true;
        }
        return false;
	}
	

	public static String UrlPage(String strURL){
		if (StringUtils.isBlank(strURL)) {
			return null;
		}
		String strPage = null;
		String[] arrSplit = null;
		strURL = strURL.trim().toLowerCase();
		arrSplit = strURL.split("[?]");
		if (strURL.length() > 0)
		{
			if (arrSplit.length > 1)
			{
				if (arrSplit[0] != null)
				{
					strPage = arrSplit[0];
				}
			}else {
				if (arrSplit[0] != null)
				{
					strPage = arrSplit[0];
				}
			}
		}
		return strPage;
	}

	/**
	 * 去掉url中的路径，留下请求参数部分
	 * 
	 * @param strURL
	 *            url地址
	 * @return url请求参数部分
	 */
	private static String TruncateUrlPage(String strURL){

		String strAllParam = null;
		String[] arrSplit = null;
		if (StringUtils.isBlank(strURL)) {
			return strAllParam;
		}
		strURL = strURL.trim().toLowerCase();
		arrSplit = strURL.split("[?]");
		if (strURL.length() > 1)
		{
			if (arrSplit.length > 1)
			{
				if (arrSplit[1] != null)
				{
					strAllParam = arrSplit[1];
				}
			}
		}
		return strAllParam;
	}

	/**
	 * 解析出url参数中的键值对 如 "index.jsp?Action=del&id=123"，解析出Action:del,id:123存入map中
	 * 
	 * @param URL
	 *            url地址
	 * @return url请求参数部分
	 */
	public static Map<String, String> URLRequest(String URL){

		Map<String, String> mapRequest = new HashMap<String, String>();
		String[] arrSplit = null;
		String strUrlParam = TruncateUrlPage(URL);
		if (strUrlParam == null)
		{
			return mapRequest;
		}
		// 每个键值为一组
		arrSplit = strUrlParam.split("[&]");
		for (String strSplit : arrSplit)
		{
			String[] arrSplitEqual = null;
			arrSplitEqual = strSplit.split("[=]");
			// 解析出键值
			if (arrSplitEqual.length > 1)
			{
				// 正确解析
				mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
			}
			else
			{
				if (StringUtils.isNotBlank(arrSplitEqual[0]))
				{
					// 只有参数没有值，不加入
					mapRequest.put(arrSplitEqual[0], "");
				}
			}
		}
		return mapRequest;
	}

    public static boolean isSlowNginx(String log, int threshold) {
        String[] arr = log.split("\"");
        if (arr.length <22) {
            return false;
        }

        try {
            if (!StringUtils.equalsIgnoreCase(arr[22], "-")) {
                String[] s= StringUtils.split(StringUtils.trim(arr[22]), " ");
                if (s.length>=2){
                    if (StringUtils.isNotBlank(StringUtils.trim(s[1])) && !StringUtils.equals(StringUtils.trim(s[1]), "-")){
                        long costTime = (long)(Double.parseDouble(StringUtils.trim(s[1])) * 1000);//s to ms
                        return costTime>threshold;
                    }
                }
            }
        }catch (Exception e){
            logger.error("isSlowNginx parse, log=[{}]", log, e);
        }
        return false;
    }


	public static XmlySpan parseLog2XmlySpan(String log,String environmentId) {
		XmlySpan xmlySpan = new XmlySpan();
		xmlySpan.setTs(System.currentTimeMillis());
		xmlySpan.setAppName("nginx-cache");
		String[] arr = log.split("\"");
		if (arr.length <22) {
			return xmlySpan;
		}
		String url =  null;
		if (arr[1].split(" ").length==3) {
			url = arr[1].split(" ")[1];
		}
		if (StringUtils.isBlank(url)) {
			return xmlySpan;
		}
		if (url.contains("/mobile/others/ca/track") ||url.contains("/mobile/others/ca/album")) {
			disposeRestUrl(xmlySpan,NginxLogParseUtil.UrlPage(url));
		}else {
			String serviceId = NginxLogParseUtil.UrlPage(url);
			xmlySpan.setServiceId(serviceId);
		}
		fillXmlySpan(environmentId, xmlySpan, arr, url);

        if (StringUtils.isNotBlank(xmlySpan.getServiceId())) {
        	xmlySpan.setServiceId(xmlySpan.getServiceId().replaceFirst("/mobile", ""));
		}
		return xmlySpan;
				
	}

	public static void fillXmlySpan(String environmentId, XmlySpan xmlySpan, String[] arr, String url) {
		xmlySpan.putAllProp(NginxLogParseUtil.URLRequest(url));
		String cookie = "";
		String userAgent="";
		if (!StringUtils.equalsIgnoreCase(arr[3], "-")) {
			xmlySpan.setTraceId(arr[3]);
		}
		if (!StringUtils.equalsIgnoreCase(arr[5], "-")) {
            xmlySpan.setSpanId(arr[5]);
        }
		if (!StringUtils.equalsIgnoreCase(arr[7], "-")) {
            xmlySpan.setParentId(arr[7]);
        }
		if (!StringUtils.equalsIgnoreCase(arr[9], "-")) {
            cookie = arr[9];
        }
		if (!StringUtils.equalsIgnoreCase(arr[11], "-")) {
            userAgent = arr[11];
        }
		if (!StringUtils.equalsIgnoreCase(arr[12], "-")) {
            String resString = StringUtils.trim(arr[12]);
            if (StringUtils.isNotBlank(resString)){
                String[] s = resString.split(" ");
                if (s.length==2){
                    xmlySpan.addProp(ClientConstants.X_B3_RESPONSE_CODE, String.valueOf(s[0]));
                }
            }
        }
		if (StringUtils.isNotBlank(arr[14])){
            String status = StringUtils.trim(arr[14]);
            if (StringUtils.isNotBlank(status)){
                String[] s=status.split(" ");
                if (s.length==3){
                    xmlySpan.addProp(ClientConstants.X_B3_HIT_NGINX_STATUS, s[1]);
                }
            }
        }

		//把server端耗时改成取upstream_response_time from张青
		if (!StringUtils.equalsIgnoreCase(arr[22], "-")) {
            String[] s= StringUtils.split(StringUtils.trim(arr[22]), " ");
            if (s.length>=2){
                long costTime = 0l;
                if (StringUtils.isNotBlank(StringUtils.trim(s[1])) && !StringUtils.equals(StringUtils.trim(s[1]), "-")){
                    costTime = (long)(Double.parseDouble(StringUtils.trim(s[1])) * 1000);//s to ms
                }
                xmlySpan.addProp(ClientConstants.X_B3_SERVER_COSTTIME, String.valueOf(costTime));
            }
        }
		if (!StringUtils.equalsIgnoreCase(arr[21], "-")) {
            xmlySpan.setViewId(arr[21]);
        }
		Map<String, String> cookiesMap =  parseCookieMap(cookie);
		RequestParameterParserUtil.fillXmlySpan(xmlySpan, cookiesMap, userAgent, environmentId);
		if (StringUtils.isNotBlank(arr[0])){
            try {
                String[] temp = arr[0].split(" ");
                if (temp.length>=5){
                    xmlySpan.addProp(ClientConstants.X_B3_CLIENT_IP, temp[0]);
                    String dateString = StringUtils.replace(temp[3], "[", "")+" "+ StringUtils.replace(temp[4], "]", "");
                    SimpleDateFormat formatter = new SimpleDateFormat("dd/MMM/yyyy:hh:mm:ss Z", Locale.ENGLISH);
                    Date date = formatter.parse(dateString);
                    xmlySpan.setTs(date.getTime());
                }
            }catch (Exception e){
                logger.error("parse nginx date meet exception", e);
            }
        }
		xmlySpan.setEventType(EventType.OTHER);
	}

	/**
	 * @param xmlySpan
	 * @param urlPage
	 */
	private static void disposeRestUrl(XmlySpan xmlySpan, String urlPage) {
		if (StringUtils.isBlank(urlPage)) {
			return;
		}
		if (!NginxLogParseUtil.checkTrackDetail(urlPage, xmlySpan)) {
			NginxLogParseUtil.checkAlbumDetail(urlPage, xmlySpan);
		}
	}

	/**
	 * @param cookie
	 * @return
	 */
	public static Map<String, String> parseCookieMap(String cookie) {
		Map<String, String> cookieMap =  new HashMap<String, String>();
		if (StringUtils.isNotBlank(cookie)) {
			cookie=cookie.replaceAll(" ", "");
			String[] pairs = cookie.split(";");
			for (int i = 0; i < pairs.length; i++) {
				String[] pair = pairs[i].split("=");
				if(pair.length==2){
					cookieMap.put(pair[0], pair[1]);
				}
				
			}
		}
		return cookieMap;
	}


}
